#ifndef SSXLIST_H_INCLUDED
#define SSXLIST_H_INCLUDED
#include <unistd.h>
#include <iostream>
template<typename Object>
class SsxList{


public:
    /*
    node of list
    */
    struct Node{
        Node * prev;
        Node * next;
        Object data;
        Node(Object d, Node * p, Node *n):data(d),prev(p),next(n){}
        Node(){prev = next = NULL;}
    };


    /*
    normal iterator
    */

    class normal_itr{
        public:
            normal_itr():current(NULL){}

            Object & operator*()
            {
                return retrieve();
            }

            normal_itr & operator++()
            {
                current = current->next;
                return *this;
            }

            normal_itr operator++(int)
            {
                normal_itr old_itr(current);
                current = current->next;
                return old_itr;
            }

        protected:
            normal_itr(Node *n):current(n){}
            Node * current;
            friend class SsxList<Object>;
            Object & retrieve()
            {
                return current->data;
            }
    };

public:
    SsxList(){
        init();

    }


    ~SsxList(){

        std::cout << "list destructor" <<std::endl;
        /*
        clear elements
        */
        while(thesize > 0)
        {
            list_pop_front();
        }


        /*
        deal with head and tail
        */
        delete head;
        delete tail;
        head = tail = NULL;



    }
    /*
    insert a object before the iterator
    */
    normal_itr insert_before(normal_itr it, Object x)
    {

        std::cout << "insert object " << x  << std::endl;

         ++thesize;
        /*
        must be node itself!!!!!
        */

        Node * nodeA = it.current;



        Node * nodeB = (it.current)->prev;


        Node * newNode = new Node(x,nodeB,nodeA);
        nodeA->prev = newNode;
        nodeB->next = newNode;
        //std::cout << nodeB->data << " head-tail "  << nodeA->data << std::endl;
        normal_itr itr(newNode);
        return itr;
    }
    /*another version of insert*/
    normal_itr insert_before2(normal_itr itr, Object x)
    {
        ++thesize;
        Node * cur = itr.current;
        Node  * newnode = new Node(x, cur->prev ,  cur);
        cur->prev->next = newnode;
        cur->prev = newnode;

        normal_itr itt(newnode);
        return itt;

    }




    /*
    check forward and backward
    */
    void check(normal_itr it)
    {
        Node * nodePrev = (it.current)->prev;
        Node * nodeNext = (it.current)->next;
        std::cout << nodePrev->data << " prev-next "  << nodeNext->data << std::endl;
    }


    /*
    remove the iterator
    */

    normal_itr remove_this(normal_itr it)
    {

        std::cout << *it ;
        --thesize;
        Node * nodePrev = (it.current)->prev;
        Node * nodeNext = (it.current)->next;
        //std::cout << nodePrev->data << " head-tail "  << nodeNext->data << std::endl;
        Node * theNode = it.current;

        nodePrev->next = nodeNext;
        nodeNext->prev = nodePrev;

        delete theNode;

        normal_itr itr(nodeNext);
        std::cout << " has been removed \n";
        return itr;

    }
    /*
    the first element not head
    */
    normal_itr list_begin()
    {
        normal_itr itr(head->next);
        return itr;

    }
    /*
    tail
    */
    normal_itr list_end()
    {
        normal_itr itr(tail);
        return itr;
    }

    /*
    pop_front
    */
    void list_pop_front()
    {
        std::cout << "pop front!" << *list_begin() << std::endl;
       if(thesize > 0)
       {

           remove_this(list_begin());
       }


    }

    /*
    push back
    */

    void list_push_back(Object & x)
    {
        normal_itr itr(tail);
        insert_before2(itr, x);
    }



private:
    /*
    build an empty list
    */
    void init()
    {
        head = new Node();
        tail = new Node();
        head->next = tail;
        tail->prev = head;
        head->data = 999;
        tail->data = 888;
        thesize = 0;
    }


    Node * head;
    Node * tail;
    int thesize;


};



#endif // SSXLIST_H_INCLUDED
